#include "../IO Interface/DataManager.h"
//#include "../optimizer_mcmf_planA/OptimizerMcmfPlanA.hpp"
using std::endl;
using std::vector;
using std::pair;
using std::min;
using std::cout;

//#define DEBUG_INPUT_OUTPUT
#define DEBUG_OTHERS

// #define TUNING

#define TRUE_DATA
//#define FAKE_DATA
//#define SMALL_DATA

// #define CMAKE
#define VISUALSTUDIO
//#define SUBMIT

#ifdef TRUE_DATA
const std::string filename = "data";
#endif
#ifdef FAKE_DATA
const std::string filename = "fake_data";
#endif
#ifdef SMALL_DATA
const std::string filename = "data-small";
#endif

#ifdef CMAKE
DataManager datamanager("../" + filename);
#endif
#ifdef VISUALSTUDIO
DataManager datamanager("../../" + filename);
#endif
#ifdef SUBMIT
DataManager datamanager("/" + filename);
#endif


void writeToFile(std::string fileName = "solution.txt")
{
#ifdef CMAKE
    datamanager.writeFile("../output/" + fileName);
#endif 
#ifdef VISUALSTUDIO
    datamanager.writeFile("../../../output/" + fileName);
#endif
#ifdef SUBMIT
    datamanager.writeFile("/output/" + fileName);
#endif
}

long beginTime = time(0);

int binarySmallCnt;
double bigK, k, momentum;
int drop_out;
int binaryTotCnt, binaryCorrectCnt;


int biggerTime, smallerTime;
int firstBinaryTotCnt, biggerBinaryTotCnt, smallerBinaryTotCnt;
int smallerBetterCnt;

int cycleCnt, binaryCnt;

int maxFlowBinaryCnt;
double maxFlowK;

double initial_speed, accelarate;

#ifndef SUBMIT

#ifdef TUNING
#include <getopt.h>

void read_opts(int argc, char * argv[]) {
    int opt;
    // int digit_optind = 0;
    int option_index = 0;
    const char *optstring = "";
    static struct option long_options[] = {
        {"cycleCnt", required_argument, NULL, 0},
        {"binaryCnt", required_argument, NULL, 0},
        {"binarySmallCnt", required_argument, NULL, 0},
        {"bigK", required_argument, NULL, 0},
        {"maxFlowBinaryCnt", required_argument, NULL, 0},
        {"initial_speed", required_argument, NULL, 0},
        {"accelarate", required_argument, NULL, 0},
        {"drop_out", required_argument, NULL, 0},
        {0, 0, 0, 0}
    };

    while ( (opt = getopt_long(argc, argv, optstring, long_options, &option_index)) != -1 ) {
        switch (option_index)
        {
        case 0:
            cycleCnt = std::atoi(argv[optind - 1]);
            break;
        case 1:
            binaryCnt = std::atoi(argv[optind - 1]);
            break;
        case 2:
            binarySmallCnt = std::atoi(argv[optind - 1]);
            break;
        case 3:
            bigK = std::atof(argv[optind - 1]);
            break;
        case 4:
            maxFlowBinaryCnt = std::atoi(argv[optind - 1]);
            break;
        case 5:
            initial_speed = std::atof(argv[optind - 1]);
            break;
        case 6:
            accelarate = std::atof(argv[optind - 1]);
            break;
        // TODO
        case 7:
            drop_out = std::atoi(argv[optind - 1]);
            break;
        }
    }
}

#endif
#endif

#ifdef DEBUG_OTHERS

int main(int argc, char * argv[]) {
    cycleCnt = 15;
    binaryCnt = 2; 
    binarySmallCnt = 4;
    bigK = 0.9;
    maxFlowK = 0.5;
    drop_out = 100;
    initial_speed = 1.1;
    accelarate = 0.1;
    maxFlowBinaryCnt = 3;
    k = 0.5;

    #ifndef SUBMIT
    #ifdef TUNING
    read_opts(argc, argv);
    #endif
    #endif

    OptimizerMcmfPlanA optimizerMcmfPlanA(&datamanager);

    std::cout << "ans: " << optimizerMcmfPlanA.solve(
        cycleCnt,
        binaryCnt, 
        k) << "\n";

    writeToFile();


    std::cout << "cycleCnt = " << cycleCnt << ", binaryCnt = " << binaryCnt << ", binarySmallCnt = " << binarySmallCnt<< ", bigK = "<< bigK << " k = " << k << ": \n";
    std::cout << "momentum = " << momentum << ", drop_out = " << drop_out << "maxFlowBinaryCnt: " << maxFlowBinaryCnt << endl;
    std::cout << "time: " << time(0) - beginTime << "\n";
    std::cout << "binary hit rate: " << (double)binaryCorrectCnt / binaryTotCnt << "\n";
    std::cout << "firstBinaryTotCnt: " << firstBinaryTotCnt << "\n";
    std::cout << "biggerBinaryTotCnt: " << biggerBinaryTotCnt << "\n";
    std::cout << "smallerBinaryTotCnt: " << smallerBinaryTotCnt << "\n";
    std::cout << "smallerBetterCnt: " << smallerBetterCnt << "\n";
    std::cout << "biggerTime: " << biggerTime << "\n";
    std::cout << "smallerTime: " << smallerTime << "\n";
    std::cout << "initial speed: " << initial_speed << "\n";
    std::cout << "accelerate: " << accelarate << "\n";

    return 0;
}

#endif // DEBUG_OTHERS

#ifdef DEBUG_INPUT_OUTPUT
int main()
{
    datamanager.debugDataManager();
    return 0;
}
#endif // DEBUG_INPUT_OUTPUT
